import tkinter as tk
from tkinter import ttk, messagebox
import pyperclip
import pandas as pd
from ttkbootstrap import Style
import threading
import re
import os
from datetime import datetime
from openpyxl import load_workbook
import queue


class IDSearchApp:
    def __init__(self, root):
        self.root = root
        self.root.title("身份证信息查询系统")
        self.root.geometry("500x450")

        # 设置窗口属性
        self.root.attributes('-toolwindow', True)
        self.root.attributes('-topmost', True)
        self.close_count = 0
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)

        # 初始化日志系统
        self.log_file = "id_search_log.txt"
        self.init_log_file()

        # 消息队列
        self.message_queue = queue.Queue()

        # 应用样式
        self.style = Style(theme='flatly')

        # 数据文件路径
        self.excel_path = self.get_latest_excel_file()

        # 初始化变量
        self.df = None
        self.data_loaded = False
        self.last_clipboard_content = ""
        self.current_id = ""
        self.wb = None
        self.ws = None
        self.id_column_idx = -1
        self.record_column_idx = -1
        self.from_clipboard = False
        self.clipboard_monitor_active = False

        # 创建界面
        self.create_widgets()

        # 加载数据
        self.load_data_thread()

        # 启动消息队列处理
        self.process_queue()

    def process_queue(self):
        try:
            while True:
                msg_type, *args = self.message_queue.get_nowait()
                if msg_type == "status":
                    self.status_var.set(args[0])
                elif msg_type == "log":
                    self.write_log(*args)
                elif msg_type == "error":
                    messagebox.showerror("错误", args[0])
                elif msg_type == "info":
                    if args and args[0] == "结果" and args[1] == "未找到匹配记录":
                        self.show_custom_messagebox(*args)
                    else:
                        messagebox.showinfo(*args)
        except queue.Empty:
            pass
        self.root.after(100, self.process_queue)

    def show_custom_messagebox(self, title, message):
        top = tk.Toplevel(self.root)
        top.title(title)
        top.geometry("400x150")

        # 计算居中位置
        window_width = 400
        window_height = 150
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        top.geometry(f"{window_width}x{window_height}+{x}+{y}")

        top.attributes('-topmost', True)

        # 使用更大的红色字体
        label = ttk.Label(
            top,
            text=message,
            font=('Microsoft YaHei', 24),
            foreground='red'
        )
        label.pack(pady=20)

        def on_ok():
            top.destroy()
            self.minimize_window()

        btn = ttk.Button(
            top,
            text="确定",
            command=on_ok,
            style='primary.TButton',
            width=10
        )
        btn.pack(pady=10)

    def show_followup_complete_message(self):
        top = tk.Toplevel(self.root)
        top.title("提示")
        top.geometry("400x150")

        # 计算居中位置
        window_width = 400
        window_height = 150
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        top.geometry(f"{window_width}x{window_height}+{x}+{y}")

        top.attributes('-topmost', True)

        # 使用更大的红色字体
        label = ttk.Label(# 创建标签控件
            top,
            text="本季度已完成随访",
            font=('Microsoft YaHei', 24),
            foreground='red'
        )
        label.pack(pady=20)

        def on_ok():
            top.destroy()

        btn = ttk.Button(
            top,
            text="确定",
            command=on_ok,
            style='primary.TButton',
            width=10
        )
        btn.pack(pady=10)

    def on_close(self):
        self.close_count += 1
        if self.close_count == 1:
            self.reset_timer = self.root.after(2000, self.reset_close_count)

        remaining = 3 - self.close_count

        if self.close_count >= 3:
            if hasattr(self, 'reset_timer'):
                self.root.after_cancel(self.reset_timer)
            self.write_log("系统操作", "程序退出")
            self.clipboard_monitor_active = False
            self.root.destroy()
        else:
            self.status_var.set(f"再点击 {remaining} 次关闭按钮将退出程序")
            self.write_log("用户操作", f"尝试关闭程序 ({self.close_count}/3)")

    def reset_close_count(self):
        if self.close_count < 3:
            self.close_count = 0
            self.status_var.set("就绪")
            self.write_log("系统操作", "关闭计数器已重置")

    def init_log_file(self):
        if not os.path.exists(self.log_file):
            with open(self.log_file, "w", encoding="utf-8") as f:
                f.write("身份证查询系统日志\n")
                f.write("=" * 50 + "\n")

    def write_log(self, action, content, result=""):
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_entry = f"[{timestamp}] {action}: {content}"
        if result:
            log_entry += f" | 结果: {result}"
        log_entry += "\n"

        with open(self.log_file, "a", encoding="utf-8") as f:
            f.write(log_entry)

        self.status_var.set(log_entry.strip())

    def create_widgets(self):
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 顶部标题和按钮
        header_frame = ttk.Frame(main_frame)
        header_frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(
            header_frame,
            text="身份证信息查询系统",
            font=('Helvetica', 16, 'bold')
        ).pack(side=tk.LEFT)

        btn_frame = ttk.Frame(header_frame)
        btn_frame.pack(side=tk.RIGHT)

        close_btn = ttk.Button(
            btn_frame,
            text="关闭程序",
            command=self.on_close,
            style='danger.TButton',
            width=8,
            padding=(0, 0)
        )
        close_btn.pack(side=tk.RIGHT, padx=5)

        ttk.Button(
            btn_frame,
            text="查看日志",
            command=self.view_logs,
            style='info.Outline.TButton',
            width=8
        ).pack(side=tk.LEFT, padx=2)

        # 搜索控制区
        control_frame = ttk.LabelFrame(
            main_frame,
            text="查询控制",
            padding=(15, 10)
        )
        control_frame.pack(fill=tk.X, pady=5)

        search_frame = ttk.Frame(control_frame)
        search_frame.pack(fill=tk.X, pady=5)

        ttk.Label(search_frame, text="身份证号:").pack(side=tk.LEFT)
        self.search_entry = ttk.Entry(search_frame, width=30)
        self.search_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

        btn_frame = ttk.Frame(search_frame)
        btn_frame.pack(side=tk.LEFT, padx=5)

        ttk.Button(
            btn_frame,
            text="查询",
            command=self.search_id,
            style='success.TButton',
            width=8
        ).pack(side=tk.LEFT, padx=2)

        ttk.Button(
            btn_frame,
            text="清空",
            command=self.clear_search,
            style='danger.TButton',
            width=8
        ).pack(side=tk.LEFT, padx=2)

        # 结果显示区
        result_frame = ttk.LabelFrame(
            main_frame,
            text="查询结果",
            padding=10
        )
        result_frame.pack(fill=tk.BOTH, expand=True)

        self.result_text = tk.Text(
            result_frame,
            wrap=tk.WORD,
            font=('Microsoft YaHei', 11),
            padx=10,
            pady=10,
            height=8,
            state=tk.DISABLED
        )
        self.result_text.pack(fill=tk.BOTH, expand=True)

        # 配置文本标签样式
        current_size = 12
        self.result_text.tag_config('header', font=('Microsoft YaHei', current_size * 2, 'bold'), foreground='red')

        # 底部按钮框架
        bottom_frame = ttk.Frame(main_frame)
        bottom_frame.pack(fill=tk.X, pady=(5, 0))

        # 修改后的"新建随访"按钮 - 变大变红
        self.follow_up_btn = ttk.Button(
            bottom_frame,
            text="新建随访",
            command=self.add_follow_up,
            style='danger.TButton',  # 红色按钮
            width=15,  # 增大宽度
            padding=(10, 5)  # 增加内边距使按钮更大
        )
        self.follow_up_btn.pack(side=tk.RIGHT, padx=10)

        self.confirm_btn = ttk.Button(
            bottom_frame,
            text="关闭窗口",
            command=self.minimize_window,
            style='danger.TButton',
            width=8
        )
        self.confirm_btn.pack(side=tk.RIGHT, padx=5)

        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("系统就绪")
        status_bar = ttk.Label(
            main_frame,
            textvariable=self.status_var,
            relief=tk.SUNKEN,
            anchor=tk.W,
            padding=(10, 5, 10, 5),
            font=('Microsoft YaHei', 9),
            style='secondary.TLabel'
        )
        status_bar.pack(fill=tk.X, pady=(5, 0))

        self.search_entry.bind('<Return>', lambda e: self.search_id())

    def add_follow_up(self):
        if not self.current_id:
            return

        try:
            row_idx = self.df.index.get_loc(self.current_id)

            if pd.isna(self.df.at[self.current_id, "检查记录登记"]):
                today = datetime.now().strftime("%Y-%m-%d %H:%M")

                self.df.at[self.current_id, "检查记录登记"] = today

                excel_row = row_idx + 2
                self.ws.cell(row=excel_row, column=self.record_column_idx + 1, value=today)
                self.wb.save(self.excel_path)

                self.search_id()
                self.follow_up_btn.config(state=tk.DISABLED, style='danger.TButton')

                self.message_queue.put(("info", "成功", f"已添加随访记录: {today}"))
                self.message_queue.put(
                    ("log", "随访记录", self.current_id[:6] + "..." + self.current_id[-4:], f"添加随访日期: {today}"))
            else:
                # 创建提示窗口 - 使用大号红色字体
                top = tk.Toplevel(self.root)
                top.title("提示")
                top.geometry("400x150")

                # 计算居中位置
                window_width = 400
                window_height = 150
                screen_width = self.root.winfo_screenwidth()
                screen_height = self.root.winfo_screenheight()
                x = (screen_width - window_width) // 2
                y = (screen_height - window_height) // 2
                top.geometry(f"{window_width}x{window_height}+{x}+{y}")

                top.attributes('-topmost', True)

                label = ttk.Label(# 创建标签控件
                    top,
                    text="该身份证已有随访记录",
                    font=('Microsoft YaHei', 24),
                    foreground='red'
                )
                label.pack(pady=20)

                def on_ok():
                    top.destroy()
                    self.minimize_window()

                btn = ttk.Button(
                    top,
                    text="确定",
                    command=on_ok,
                    style='primary.TButton',
                    width=10
                )
                btn.pack(pady=10)

        except Exception as e:
            self.message_queue.put(("error", f"添加随访记录失败: {str(e)}"))
            self.message_queue.put(("log", "随访错误", self.current_id[:6] + "..." + self.current_id[-4:], str(e)))

    def minimize_window(self):
        self.root.withdraw()
        self.write_log("用户操作", "窗口隐藏")

    def restore_window(self):
        if not self.root.winfo_viewable():
            self.root.deiconify()
            self.root.attributes('-topmost', True)
            self.write_log("系统操作", "窗口已恢复")

    def view_logs(self):
        try:
            with open(self.log_file, "r", encoding="utf-8") as f:
                logs = f.read()

            log_window = tk.Toplevel(self.root)
            log_window.title("查询日志")
            log_window.geometry("800x600")
            log_window.attributes('-topmost', True)

            text_frame = ttk.Frame(log_window)
            text_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

            log_text = tk.Text(
                text_frame,
                wrap=tk.WORD,
                font=('Courier New', 10)
            )
            log_text.pack(fill=tk.BOTH, expand=True)
            log_text.insert(tk.END, logs)
            log_text.config(state=tk.DISABLED)

            btn_frame = ttk.Frame(log_window)
            btn_frame.pack(fill=tk.X, padx=10, pady=(0, 10))

            ttk.Button(
                btn_frame,
                text="关闭",
                command=log_window.destroy,
                style='danger.TButton'
            ).pack(side=tk.RIGHT)

        except Exception as e:
            self.message_queue.put(("error", f"无法读取日志文件: {str(e)}"))

    def start_clipboard_monitor(self):
        self.clipboard_monitor_active = True
        self.monitor_clipboard()

    def monitor_clipboard(self):
        if not hasattr(self, 'clipboard_monitor_active') or not self.clipboard_monitor_active:
            return

        if not hasattr(self, 'df') or self.df is None:
            self.root.after(300, self.monitor_clipboard)
            return

        try:
            current_content = pyperclip.paste().strip()

            if (current_content != self.last_clipboard_content and
                    self.is_valid_id_number(current_content)):

                if current_content in self.df.index:
                    record = self.df.at[current_content, "检查记录登记"]
                    has_follow_up = not pd.isna(record) and str(record).strip() != ""

                    if has_follow_up:
                        self.write_log("剪贴板检测到已有随访记录的身份证号",
                                       current_content[:6] + "..." + current_content[-4:])
                        self.last_clipboard_content = current_content
                        # 弹出"本季度已完成随访"提示框
                        self.show_followup_complete_message()
                        self.root.after(300, self.monitor_clipboard)
                        return

                self.from_clipboard = True
                self.restore_window()
                self.search_entry.delete(0, tk.END)
                self.search_entry.insert(0, current_content)
                self.write_log("剪贴板检测到身份证号", current_content[:6] + "..." + current_content[-4:])
                self.search_id()
                self.last_clipboard_content = current_content
                self.from_clipboard = False

        except Exception as e:
            error_msg = f"剪贴板监控错误: {e}"
            print(error_msg)
            self.write_log("系统错误", error_msg)

        self.root.after(300, self.monitor_clipboard)

    def get_latest_excel_file(self):
        current_dir = os.getcwd()
        xlsx_files = [f for f in os.listdir(current_dir) if f.endswith('.xlsx')]

        if xlsx_files:
            return os.path.join(current_dir, xlsx_files[0])
        else:
            raise FileNotFoundError("未找到任何 .xlsx 文件")

    def is_valid_id_number(self, text):
        pattern = r'^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$'
        return re.match(pattern, text) is not None

    def load_data_thread(self):
        self.message_queue.put(("status", "正在加载数据文件..."))
        self.message_queue.put(("log", "系统操作", "开始加载数据文件"))
        threading.Thread(target=self.load_data, daemon=True).start()

    def load_data(self):
        try:
            self.df = pd.read_excel(
                self.excel_path,
                engine='openpyxl',
                dtype={'证件号码': str}
            )

            if '证件号码' in self.df.columns:
                self.df['证件号码'] = self.df['证件号码'].astype(str).str.strip()
                self.df.set_index('证件号码', inplace=True, drop=False)

            if '检查记录登记' not in self.df.columns:
                self.df['检查记录登记'] = pd.NA

                self.wb = load_workbook(self.excel_path)
                self.ws = self.wb.active

                for idx, cell in enumerate(self.ws[1]):
                    if cell.value == "证件号码":
                        self.id_column_idx = idx

                new_col = self.ws.max_column + 1
                self.ws.cell(row=1, column=new_col, value="检查记录登记")
                self.record_column_idx = new_col - 1
                self.wb.save(self.excel_path)
                self.message_queue.put(("log", "系统操作", "已添加'检查记录登记'列"))
            else:
                self.wb = load_workbook(self.excel_path)
                self.ws = self.wb.active

                for idx, cell in enumerate(self.ws[1]):
                    if cell.value == "证件号码":
                        self.id_column_idx = idx
                    elif cell.value == "检查记录登记":
                        self.record_column_idx = idx

            self.data_loaded = True
            msg = f"数据加载完成 | 共 {len(self.df)} 条记录"
            self.message_queue.put(("status", msg))
            self.message_queue.put(("log", "系统操作", msg))

            self.start_clipboard_monitor()

        except Exception as e:
            error_msg = f"加载数据失败: {str(e)}"
            self.message_queue.put(("error", error_msg))
            self.message_queue.put(("status", error_msg))
            self.message_queue.put(("log", "系统错误", error_msg))

            try:
                self.try_repair_excel()
            except Exception as repair_error:
                self.message_queue.put(("log", "系统错误", f"尝试修复Excel文件失败: {str(repair_error)}"))

    def try_repair_excel(self):
        try:
            temp_df = pd.read_excel(self.excel_path, engine='xlrd')
            new_path = os.path.splitext(self.excel_path)[0] + "_repaired.xlsx"
            temp_df.to_excel(new_path, index=False)
            self.excel_path = new_path
            self.message_queue.put(("log", "系统操作", f"已修复并保存文件为: {new_path}"))
            self.load_data()
        except Exception as e:
            raise Exception(f"无法修复Excel文件: {str(e)}")

    def clear_search(self):
        self.search_entry.delete(0, tk.END)
        self.result_text.config(state=tk.NORMAL)
        self.result_text.delete(1.0, tk.END)
        self.result_text.config(state=tk.DISABLED)
        self.status_var.set("已清空搜索条件")
        self.write_log("用户操作", "清空搜索条件")
        self.current_id = ""
        self.follow_up_btn.config(state=tk.DISABLED, style='danger.TButton')

    def search_id(self):
        if not hasattr(self, 'df') or self.df is None:
            self.message_queue.put(("error", "数据尚未加载完成，请稍后再试"))
            return

        if not self.data_loaded:
            self.message_queue.put(("info", "警告", "数据尚未加载完成，请稍后再试"))
            return

        id_number = self.search_entry.get().strip()
        if not id_number:
            self.message_queue.put(("error", "请输入身份证号"))
            return

        if not self.is_valid_id_number(id_number):
            error_msg = "无效的身份证号格式"
            self.message_queue.put(("error", error_msg))
            self.write_log("查询错误", id_number[:6] + "..." + id_number[-4:], error_msg)
            return

        self.status_var.set(f"正在查询: {id_number[:6]}...{id_number[-4:]}")
        self.root.update_idletasks()

        try:
            self.result_text.config(state=tk.NORMAL)
            self.result_text.delete(1.0, tk.END)

            if id_number in self.df.index:
                self.current_id = id_number
                result = self.df.loc[[id_number]]

                follow_up_record = result.iloc[0]["检查记录登记"]
                has_follow_up = not pd.isna(follow_up_record) and str(follow_up_record).strip() != ""

                if has_follow_up:
                    self.follow_up_btn.config(state=tk.NORMAL, style='danger.TButton')
                else:
                    self.follow_up_btn.config(state=tk.NORMAL, style='danger.TButton')

                if has_follow_up and self.from_clipboard:
                    self.minimize_window()
                    return

                first_column_name = self.df.columns[0]
                first_column_value = str(result.iloc[0][first_column_name])

                self.result_text.insert(tk.END, f"{first_column_value}\n", 'header')

                for col_name, value in result.iloc[0].items():
                    if col_name == first_column_name or pd.isna(value) or str(value).strip() == "":
                        continue
                    self.result_text.insert(tk.END, f"{col_name}: {value}\n")

                self.result_text.see(tk.END)

                log_data = " | ".join(
                    [str(x) if pd.notna(x) and str(x).strip() != "" else "" for x in result.iloc[0].values])
                success_msg = f"查询结果: {log_data}"
                self.status_var.set("查询成功")
                self.write_log("查询成功", id_number[:6] + "..." + id_number[-4:], success_msg)
            else:
                not_found_msg = "未找到匹配记录"
                self.result_text.insert(tk.END, not_found_msg + "\n")
                self.status_var.set(f"未找到身份证号: {id_number[:6]}...{id_number[-4:]}")
                self.message_queue.put(("info", "结果", not_found_msg))
                self.write_log("查询结果", id_number[:6] + "..." + id_number[-4:], not_found_msg)
                self.current_id = ""
                self.follow_up_btn.config(state=tk.DISABLED, style='danger.TButton')

            self.result_text.config(state=tk.DISABLED)

        except Exception as e:
            error_msg = f"查询失败: {str(e)}"
            self.message_queue.put(("error", error_msg))
            self.status_var.set(f"查询出错: {str(e)}")
            self.write_log("查询错误", id_number[:6] + "..." + id_number[-4:], error_msg)
            self.current_id = ""
            self.follow_up_btn.config(state=tk.DISABLED, style='danger.TButton')


if __name__ == "__main__":
    root = tk.Tk()
    app = IDSearchApp(root)
    root.mainloop()